package com.igoal.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.igoal.entity.DataStatus;
import com.igoal.entity.Goal;

@Repository("goalDAO")
public class GoalDAOImpl extends GenericDaoHibernate<Goal, Long> implements
		GoalDAO {

	public GoalDAOImpl() {
		super(Goal.class);
	}

	public boolean exists(String title) {
		if(title == null) return false;
		
		DetachedCriteria dc = DetachedCriteria.forClass(Goal.class);
		dc.add(Restrictions.ilike("title", title, MatchMode.EXACT));
//		getByStatus(dc, DataStatus.USING);
		if(findByCriteria(dc).size() > 0) return true;
		
		return false;
	}

	public Goal findByTitle(String title) {
		if(title == null) return null;
		
		DetachedCriteria dc = DetachedCriteria.forClass(Goal.class);
		dc.add(Restrictions.ilike("title", title, MatchMode.EXACT));
		getByStatus(dc, DataStatus.USING);
		
		List<Goal> result = findByCriteria(dc);
		
		if(result.size() == 0) return null;
		
		return result.get(0);
	}
	
	public List<Goal> findByTitle(String title, MatchMode matchMode, int numberOfGoals){
		if(title == null) return null;
		
		DetachedCriteria dc = DetachedCriteria.forClass(Goal.class);
		dc.add(Restrictions.ilike("title", title, matchMode));
		dc.addOrder(Order.asc("userCount"));
		getByStatus(dc, DataStatus.USING);
		
		List<Goal> result = null;
		
		if(numberOfGoals <= 0){
			result = findByCriteria(dc);
		}else{
			result = findByCriteria(dc, 0, numberOfGoals);
		}
		
		return result;
	}

	public List<Goal> findTopGoals(int numberOfGoals) {
		if(numberOfGoals < 0) return null;
		
		DetachedCriteria dc = DetachedCriteria.forClass(Goal.class);
		dc.addOrder(Order.desc("userCount"));
		getByStatus(dc, DataStatus.USING);
		
		return findByCriteria(dc, 0, numberOfGoals);
	}
	
	@SuppressWarnings("unchecked")
	public List<Goal> getShouldDoGoals(int numberOfGoals, long userId) {
		if(numberOfGoals < 0) {
			return null;
		}
		
		String findTopGoalQuery = "from com.igoal.entity.Goal goal where goal.id not in " 
			+ "(select usergoal.pk.goal.id from com.igoal.entity.UserGoal usergoal where usergoal.pk.user.id =" + userId + ") ";
		
		String findTopGoalInUserCategoryQuery = findTopGoalQuery
			+ "and goal.id in (select goalcategory.pk.goal.id from com.igoal.entity.GoalCategory goalcategory where goalcategory.pk.goal.status = 'USING' and goalcategory.pk.category.id in (select usercategory.pk.category.id from com.igoal.entity.UserCategory usercategory where usercategory.pk.user.id="+userId+")) ";
		
		String order = "order by RAND()";
		
		@SuppressWarnings("rawtypes")
		List list = getHibernateTemplate().find(findTopGoalInUserCategoryQuery + order);
		
		if(list.isEmpty()){
			list = getHibernateTemplate().find(findTopGoalQuery + order);
		}
		
		return list;
	}
	
	public int countGoalsFrom(Date date){
		DetachedCriteria dc = DetachedCriteria.forClass(Goal.class);
		dc.add(Restrictions.ge("createDate", date));
		getByStatus(dc, DataStatus.USING);
		
		return countByCriteria(dc);
	}
	
	public List<Goal> getRandomGoals(int maxGoals){
		DetachedCriteria dc = DetachedCriteria.forClass(Goal.class);
		getByStatus(dc, DataStatus.USING);
		getRandomEntities(dc);
		return findByCriteria(dc, 0, maxGoals);
	}
}
